/*
* Copyright (C) 2012-2014 qar
* License: http://www.gnu.org/licenses/gpl.html GPL version 2
*/

#include "crypto/ciphers/encryptoraes.h"
#include "crypto/ciphers/aes.h"
#include "crypto/ciphers/common.h"

EncryptorAes::EncryptorAes(QByteArray aKey, QByteArray aIv)
	: key(aKey), iv(aIv)
{
	if (key.length() < keySize()) {
		exit(1);
	}
	key.resize(keySize());
	ctx = new (struct aes_ctx);
	memset(ctx, 0, sizeof(*ctx));
	if (iv.isEmpty()) {
		iv.resize(AES_IV_SIZE);
		generate_random_iv((u8*)iv.data(), iv.length());
	}
	aes_init_context(ctx, (const u8*)key.constData(), keySize(), cipher_mode_ctr, (const u8*)iv.constData());
}

EncryptorAes::~EncryptorAes()
{
	key.fill(0, key.length());
	iv.fill(0, iv.length());
	memset(ctx, 0, sizeof(*ctx));
	delete ctx;
	ctx = NULL;
}

qint64 EncryptorAes::blockSize() const
{
	return AES_BLOCK_SIZE;
}

qint64 EncryptorAes::keySize() const
{
	return AES_KEYSIZE_256;
}

QString EncryptorAes::getAlgorithmName() const
{
	return "AES-256";
}

void EncryptorAes::encrypt(const QByteArray &clearText, QByteArray &cipherText)
{
	cipherText.resize(clearText.length());
	aes_encrypt_buffer(ctx, (u8*)cipherText.data(), (const u8*)clearText.constData(), clearText.length());
}

void EncryptorAes::decrypt(const QByteArray &cipherText, QByteArray &clearText)
{
	clearText.resize(cipherText.length());
	aes_decrypt_buffer(ctx, (u8*)clearText.data(), (const u8*)cipherText.constData(), cipherText.length());
}

bool EncryptorAes::toStream(QDataStream &s)
{
	s << iv;

	return s.status() == QDataStream::Ok;
}

bool EncryptorAes::fromStream(QDataStream &s) {
	s >> iv;
	if (s.status() != QDataStream::Ok)
		return false;
	if (iv.length() != AES_IV_SIZE)
		return false;
	aes_init_context(ctx, (const u8*)key.constData(), keySize(), cipher_mode_ctr, (const u8*)iv.constData());
	return true;
}
